//
// * Copyright (c) 2002-2009 "Neo Technology,"
// *     Network Engine for Objects in Lund AB [http://neotechnology.com]
// *
// * This file is part of Neo4j.
// * 
// * Neo4j is free software: you can redistribute it and/or modify
// * it under the terms of the GNU Affero General Public License as
// * published by the Free Software Foundation, either version 3 of the
// * License, or (at your option) any later version.
// * 
// * This program is distributed in the hope that it will be useful,
// * but WITHOUT ANY WARRANTY; without even the implied warranty of
// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// * GNU Affero General Public License for more details.
// * 
// * You should have received a copy of the GNU Affero General Public License
// * along with this program. If not, see <http://www.gnu.org/licenses/>.
// 
namespace org.neo4j.kernel.impl.core
{


	using Node = org.neo4j.graphdb.Node;
	using NotFoundException = org.neo4j.graphdb.NotFoundException;
	using Transaction = org.neo4j.graphdb.Transaction;
	using AbstractNeo4jTestCase = org.neo4j.kernel.impl.AbstractNeo4jTestCase;

	public class TestNode : AbstractNeo4jTestCase
	{
		public TestNode(string testName) : base(testName)
		{
		}

		public virtual void testNodeCreateAndDelete()
		{
			int nodeId = -1;
			Node node = getGraphDb().createNode();
			nodeId = (int) node.getId();
			getGraphDb().getNodeById(nodeId);
			node.delete();
			Transaction tx = getTransaction();
			tx.success();
			tx.finish();
			setTransaction(getGraphDb().beginTx());
			try
			{
				getGraphDb().getNodeById(nodeId);
				fail("Node[" + nodeId + "] should be deleted.");
			}
			catch (NotFoundException e)
			{
			}
		}

		public virtual void testDeletedNode()
		{
		// do some evil stuff
			Node node = getGraphDb().createNode();
			node.delete();
			Logger log = Logger.getLogger("org.neo4j.kernel.impl.core.NeoConstraintsListener");
			Level level = log.getLevel();
			log.setLevel(Level.OFF);
			try
			{
				node.setProperty("key1", new int(1));
				fail("Adding stuff to deleted node should throw exception");
			}
			catch (Exception e)
			{ // good
			}
			log.setLevel(level);
		}

		public virtual void testNodeAddProperty()
		{
			Node node1 = getGraphDb().createNode();
			Node node2 = getGraphDb().createNode();
			try
			{
				node1.setProperty(null, null);
				fail("Null argument should result in exception.");
			}
			catch (IllegalArgumentException e)
			{
			}
			string key1 = "key1";
			string key2 = "key2";
			string key3 = "key3";
			int int1 = new int(1);
			int int2 = new int(2);
			string string1 = new string("1");
			string string2 = new string("2");

		// add property
			node1.setProperty(key1, int1);
			node2.setProperty(key1, string1);
			node1.setProperty(key2, string2);
			node2.setProperty(key2, int2);
			assertTrue(node1.hasProperty(key1));
			assertTrue(node2.hasProperty(key1));
			assertTrue(node1.hasProperty(key2));
			assertTrue(node2.hasProperty(key2));
			assertTrue(!node1.hasProperty(key3));
			assertTrue(!node2.hasProperty(key3));
			assertEquals(int1, node1.getProperty(key1));
			assertEquals(string1, node2.getProperty(key1));
			assertEquals(string2, node1.getProperty(key2));
			assertEquals(int2, node2.getProperty(key2));

			getTransaction().failure();
		}

		public virtual void testNodeRemoveProperty()
		{
			string key1 = "key1";
			string key2 = "key2";
			int int1 = new int(1);
			int int2 = new int(2);
			string string1 = new string("1");
			string string2 = new string("2");

			Node node1 = getGraphDb().createNode();
			Node node2 = getGraphDb().createNode();

			try
			{
				if (node1.removeProperty(key1) != null)
				{
					fail("Remove of non existing property should return null");
				}
			}
			catch (NotFoundException e)
			{
			}
			try
			{
				node1.removeProperty(null);
				fail("Remove null property should throw exception.");
			}
			catch (IllegalArgumentException e)
			{
			}

			node1.setProperty(key1, int1);
			node2.setProperty(key1, string1);
			node1.setProperty(key2, string2);
			node2.setProperty(key2, int2);
			try
			{
				node1.removeProperty(null);
				fail("Null argument should result in exception.");
			}
			catch (IllegalArgumentException e)
			{
			}

		// test remove property
			assertEquals(int1, node1.removeProperty(key1));
			assertEquals(string1, node2.removeProperty(key1));
		// test remove of non exsisting property
			try
			{
				if (node2.removeProperty(key1) != null)
				{
					fail("Remove of non existing property return null.");
				}
			}
			catch (NotFoundException e)
			{
			// must mark as rollback only
			}
			getTransaction().failure();
		}

		public virtual void testNodeChangeProperty()
		{
			string key1 = "key1";
			string key2 = "key2";
			string key3 = "key3";
			int int1 = new int(1);
			int int2 = new int(2);
			string string1 = new string("1");
			string string2 = new string("2");
			bool bool1 = new bool(true);
			bool bool2 = new bool(false);

			Node node1 = getGraphDb().createNode();
			Node node2 = getGraphDb().createNode();
			node1.setProperty(key1, int1);
			node2.setProperty(key1, string1);
			node1.setProperty(key2, string2);
			node2.setProperty(key2, int2);

			try
			{
				node1.setProperty(null, null);
				fail("Null argument should result in exception.");
			}
			catch (IllegalArgumentException e)
			{
			}
			catch (NotFoundException e)
			{
				fail("wrong exception");
			}

		// test change property
			node1.setProperty(key1, int2);
			node2.setProperty(key1, string2);
			assertEquals(string2, node2.getProperty(key1));
			node1.setProperty(key3, bool1);
			node1.setProperty(key3, bool2);
			assertEquals(string2, node2.getProperty(key1));
			node1.delete();
			node2.delete();
		}

		public virtual void testNodeChangeProperty2()
		{
			string key1 = "key1";
			int int1 = new int(1);
			int int2 = new int(2);
			string string1 = new string("1");
			string string2 = new string("2");
			bool bool1 = new bool(true);
			bool bool2 = new bool(false);
			Node node1 = getGraphDb().createNode();
			node1.setProperty(key1, int1);
			node1.setProperty(key1, int2);
			assertEquals(int2, node1.getProperty(key1));
			node1.removeProperty(key1);
			node1.setProperty(key1, string1);
			node1.setProperty(key1, string2);
			assertEquals(string2, node1.getProperty(key1));
			node1.removeProperty(key1);
			node1.setProperty(key1, bool1);
			node1.setProperty(key1, bool2);
			assertEquals(bool2, node1.getProperty(key1));
			node1.removeProperty(key1);
			node1.delete();
		}

		public virtual void testNodeGetProperties()
		{
			string key1 = "key1";
			string key2 = "key2";
			string key3 = "key3";
			int int1 = new int(1);
			int int2 = new int(2);
			string @string = new string("3");

			Node node1 = getGraphDb().createNode();
			assertTrue(!node1.getPropertyValues().GetEnumerator().MoveNext());
			try
			{
				node1.getProperty(key1);
				fail("get non existing property din't throw exception");
			}
			catch (NotFoundException e)
			{
			}
			try
			{
				node1.getProperty(null);
				fail("get of null key din't throw exception");
			}
			catch (IllegalArgumentException e)
			{
			}
			assertTrue(!node1.hasProperty(key1));
			assertTrue(!node1.hasProperty(null));
			node1.setProperty(key1, int1);
			node1.setProperty(key2, int2);
			node1.setProperty(key3, @string);
			Iterator<object> values = node1.getPropertyValues().GetEnumerator();
			values.Current;
			values.Current;
			values.Current;
			Iterator<string> keys = node1.getPropertyKeys().GetEnumerator();
			keys.Current;
			keys.Current;
			keys.Current;
			assertTrue(node1.hasProperty(key1));
			assertTrue(node1.hasProperty(key2));
			assertTrue(node1.hasProperty(key3));
			try
			{
				node1.removeProperty(key3);
			}
			catch (NotFoundException e)
			{
				fail("Remove of property failed.");
			}
			assertTrue(!node1.hasProperty(key3));
			assertTrue(!node1.hasProperty(null));
			node1.delete();
		}

		public virtual void testAddPropertyThenDelete()
		{
			Node node = getGraphDb().createNode();
			node.setProperty("test", "test");
			Transaction tx = getTransaction();
			tx.success();
			tx.finish();
			tx = getGraphDb().beginTx();
			node.setProperty("test2", "test2");
			node.delete();
			tx.success();
			tx.finish();
			setTransaction(getGraphDb().beginTx());
		}

		public virtual void testChangeProperty()
		{
			Node node = getGraphDb().createNode();
			node.setProperty("test", "test1");
			newTransaction();
			node.setProperty("test", "test2");
			node.removeProperty("test");
			node.setProperty("test", "test3");
			assertEquals("test3", node.getProperty("test"));
			node.removeProperty("test");
			node.setProperty("test", "test4");
			newTransaction();
			assertEquals("test4", node.getProperty("test"));
		}

		public virtual void testChangeProperty2()
		{
			Node node = getGraphDb().createNode();
			node.setProperty("test", "test1");
			newTransaction();
			node.removeProperty("test");
			node.setProperty("test", "test3");
			assertEquals("test3", node.getProperty("test"));
			newTransaction();
			assertEquals("test3", node.getProperty("test"));
			node.removeProperty("test");
			node.setProperty("test", "test4");
			newTransaction();
			assertEquals("test4", node.getProperty("test"));
		}
	}
}